{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.models import Sequential\n",
    "from keras import optimizers\n",
    "from keras.layers import Dense, Activation, Flatten, Conv2D, MaxPooling2D, AveragePooling2D, GlobalMaxPooling2D, ZeroPadding2D, Input\n",
    "from keras.models import Model\n",
    "from keras.preprocessing import image"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 0. Basics\n",
    "- Input of image-format data is usually 4-D array in Tensorflow\n",
    "<br> **(num_instance, width, height, depth)** </br>\n",
    "    - **num_instance:** number of data instances. Usually designated as **None** to accomodate fluctuating data size\n",
    "    - **width:** width of an image\n",
    "    - **height:** height of an image\n",
    "    - **depth:** depth of an image. Color images are usually with depth = 3 (3 channels for RGB). Black/white images are usually with depth = 1 (only one channel)\n",
    "    \n",
    "<img src=\"http://xrds.acm.org/blog/wp-content/uploads/2016/06/Figure1.png\" style=\"width: 400px\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Loading image\n",
    "    - Images can be loaded using load_img() function\n",
    "    - Images can be converted to numpy array using img_to_array() function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = image.load_img('dog.jpg', target_size = (100, 100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n3sSqN2gXzSc++b3D1RVDuH37zud+/pe+9DtfPT7cccXJu4l0QRbff7ebB3h898m3v/3tUxfOraz2\nT58aelns3r4xLIq1EotUbwyqd27svvBdH3vjt7/27IWPe6QE2g0Q7pDLkwe0FvA7zHhwYATmROwP\nhntGiCYaRZMDNKXcBWNiBiRegMwTrrOrxHAFQwXcQmogAggZJyUmLwAJUoalQCuIrDbn1qnj1r3+\n6rvk8ctf//rRrZs/+r/8wSWtgW938vTW9b0XL25cfv6pf/DrL/3x7/+eX/mpX0Py7E7ecYfYqwID\nU3ZkTomEwBeCXMqg+Mq163eb5kNnLmhRzvYnNyZxfO6xYVUqy7uH03FY7jTyn/2nf+ezf/U00Sqy\nK4UMi4DUmiilrOZxoGKGMIJhvVichrPLXFVVHlXjndk9gxWHUDDSosYytCYlbavYs48/+867r0/j\nMTO6llJhDoEMFBDMBCmSBnYViyu5qJzzSRGcEtTmEdg7D+bgZLJ+i1gaLjJkzgxL71wbZ4na8Vde\n+fZGkLfeu/7//IWf+XN/6tPv/uznXn7lzUvnzt658bbR+v/l//oTJQ8Wk2NXVoS0Mh6LQoy5Tov/\n7Mf/g6+99IWi2viXP/9LAK1j+qVf/OIs51Obo4OPffC5Jy7f2Jv+0k99/h//7b9+69o7L3/py/OV\nJ9b51FtvvfHX/tb/7dy5wfGsqShthfEkx3dffeu5Dz/dpvje9Ztnzpx96+23p3emz3/20zv1LM6/\n8ann/sju3oEc5ubmfLG//N2XvlkEfev6DXD8g3/i+935RtPyxq0r22cvP7E2urdz17XaFMq97JvA\nRXYNhinvVDk5GySfAgyZ0QNrRoSD2tRDWBGXXD9am0grdDHVhCvR5qstb7zdwqUPPdb/7f/wL/3o\nf/uTv/qZv/C9/+yn/lmuy6PD/mc//cnv+dQPVFX/2WfO7C2aJ05vzeYHh614iKD56o2bZ88/qup6\n/XI+n6+NrPK9T3zo4s7O3iuvvfv8Rz9SVWFjbevtt1/92X/+hbcnuyj8pd95+fDu7W++ceXmvSs/\n+sN/7//xX/xD84N42z1xdiPfvrNI8co7NyYtXHttNi56g2bz7teuPPnIo//8//2L1z+wz5h+87eu\n/NIv/Pif/vN/bn59cvrM8Bv37n3wuz9St7B65uLHXnju1Xd/753Xr3/397x4/a23n3v8qVtpWbDi\n537j/yQlMQFScILR3BzmDmNBW6jNmFcrF1y2pO2/+tmv/Nhf+wu/+5WXvv/TP3g8rYeFv37vxsrq\noD4+Ord16Xe+/Fuvfv3lL/zCl//Zr/1aG/id135vY9TUB3vF6sWDORWjQcp2+8rrj26vrW6Ndyf1\nvTuLpp4a6vd86jOvfPPVj336u69ce6/qD2KMg8Fg4HD/3u7Pfu6nP/nJj/lquLF1VrI7Ptr9+Mc/\n+JM/8d9d+siL+zffu/zkM5D9E09f/Na791ZGBlRWiIHwnffeObe+cZQpxaWTxZtvv7m+uX7+wqPz\n6aLsr7WZk4JA7rmy3n0vJryn9uaXvsyqr77+2vd85hMvv/Kt1a3t7/vuz/zTn/hvfu5n/sl/9d/8\n5DOf+cRWVX79d7+Gxzd+58b1O6dXt6+9+876Y5fXz5w7vLOflvvj8cWjxd12kiRlGvUQbH60s7Z5\nbm/3OBQ95NbFdu3U+XeuXEkHhzfvHRYpmS6f/aM/UK0hi/AsH8j80qXLzXySFvXhbH79vSmmhSwm\nrgpbg2qndmXpodn//G/93kc+9tELT17Kltc3N4qiSCltjfrvfuvbp1bP/+Zv/Paf/9F/Y+/wEBH2\n9/a+9dar3/e9f/ww1u3xbOXcxRUHsnuLTl06aqa5rgY9OX9xWB/a53/9N8vVM9wvF/duj1Y2j/dv\n3929W/TXPvGxj8YiHN6dH7UzlLzeG3z75vW1MvyXf+/v3Lp79Ec+/QP/m7/yZ28dZ9GGKF6+9Mza\nhv/Wm2+u9oph3wJ6/MWf+DuCdOHJpy8/8uRsNmvTjdHmRYiD5vj2nd392WzmqgFQUXiM9ezU1mD/\nKOJyvrIy2p9Pimrr1sHu2IVls/zIsx+6efU1geL02dWD/cNhb31lLRwczi5vrP/FH/rXlkh//W/9\nJ5F79Wy6MuqvF6LLxWET9+f16rD66Ec/fvXGzZX19SbF/mjzZ37mX776tS/+H//m/35exw988Dlp\n5zfu3Ezz+de/+PnTa6e/+4d+WLnIlHPOt778O1/99Z//c3/jP0qr56teuP7um6fGeO3G7gvPfebK\n1avnHjmbUeN02qqb7N7ePH12sLbNnITM1E3v3bp27TqwPHrxBTBvoL0h933ePaw3tkfLg2lx7tQ3\nf+WXP/SpPzI/2F09f0bqBq+99tKoZ8C9uWDV78+ODvpFXzJIal7/8hebuDx77jEoBsmhzR3ZnaO9\nO0d13n70iceevPjOGzdI5qEazyY1OUQHliHl6Sc++fF3rl5xNgikL//2l379Vz7/J//Mj/ROb8VY\n90sauP7B3h2opzDaLFe3YLFn7Wywvr5yartFtz0aHN+4/vJLn//ql16i/vizf+pHLp897RFWRsPt\nS6cM3L39ZVb4zV//1S/8wk/l3WZ9e+vf+t/9tac++X1f+NpLH/nI8//sv/6vN09v/9Ef/HTbNrWk\n9f54sZC6TpiXoTforWwBtdmk11v56i/8wosvfPT67N4Hnnju4GAv55hVju7dXj91eePU6obqexZn\nV67hcGtrpbhxdG9zPMab7319KGv3Dl51q6coFKvV1nx3Z7Ta2zuYfOVzP/PutTc3NlfKje3VjfPM\n1C5Gm2vV3nSxeuHCGO7u78PmqH8ssXBFtkyDYTOdMmqKMAj9hV6t+tvV+FRemFp9OKvH/f7tm1cu\nb5w+bnfv3Lpy7uKHy8Fmns/Ru/54dWNjfTo7/PKv/vZ7b77xkRe+6+hgNjh9/tnv+cSl7eG4p196\n6Sti8bHHPlAvzIeVf/7f/dTdt/f/1df+Xx9/7pnXXvrtSxdO/cOf/eW26PWtQq6SHiaxWTs5VRW1\nFNPjSUF5tLZRCwO1hSFFmi4PkNyNe9ef+8iLB4d320beu36vMP2P/9P/87/3H/z7g6Odf/KF3/zg\nufNXdw6euvzIv/ljP/aP/u7fx3df+1JvfWtx86C3KtPa2Fnph2BJ0/wbX3j3+Na3ppN9seUkOVN6\n6tHzVfA42HzzzffWVmXrsY/t3bxx/vEPSKpVlqP1Vcm8trlpbbz13hVX2umz52LC4fpmrqNzzgTu\nXn8NmVD97t1rK6cvFMMRtnk4HvXHg9g266vjK9f3FpP6wtmN8Whj9+6d3njwzTdeWR1Va2trRzev\nfOWlLx1dffvpT/0vdFEulvHoePbBD1x4971rw9H6D/6FH3GjsizDfDKtyrLwsLd/x4reRq+3u3Mg\nYpvbq8SVAqbUqmaPlAEFioKbyd4BlSWIapY7e5MPP/eRn/vnn1tZWfne7/3e119/vehVq+trp7fP\n/38A+AeG8RlmPacAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<PIL.Image.Image image mode=RGB size=100x100 at 0x2340E2E93C8>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "img"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = image.img_to_array(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(100, 100, 3)\n"
     ]
    }
   ],
   "source": [
    "print(img.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Padding\n",
    "- Two types of padding options\n",
    "    - **'valid'**: no padding (drop right-most columns & bottom-most rows)\n",
    "    - **'same'**: padding size **p = [k/2]** when kernel size = **k**\n",
    "- Customized paddings can be given with ZeroPadding**n**D layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# when padding = 'valid'\n",
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'valid'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 8, 8, 10)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# when padding = 'same'\n",
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'same'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 10, 10, 10)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# user-customized padding\n",
    "input_layer = Input(shape = (10, 10, 3))\n",
    "padding_layer = ZeroPadding2D(padding = (1,1))(input_layer)\n",
    "\n",
    "model = Model(inputs = input_layer, outputs = padding_layer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 12, 12, 3)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. FIlter/kernels\n",
    "- Number of filters can be designated\n",
    "- Number of filters equals to the **depth of next layer**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# when filter size = 10\n",
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'same'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 10, 10, 10)\n"
     ]
    }
   ],
   "source": [
    "# you could see that the depth of output = 10\n",
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# when filter size = 20\n",
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 20, kernel_size = (3,3), strides = (1,1), padding = 'same'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 10, 10, 20)\n"
     ]
    }
   ],
   "source": [
    "# you could see that the depth of output = 20\n",
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Pooling\n",
    "- Usually, max pooling is applied for rectangular region\n",
    "- pooling size, padding type, and strides can be set similar to convolutional layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'same'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 10, 10, 10)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# when 'strides' parameter is not defined, strides are equal to 'pool_size'\n",
    "model.add(MaxPooling2D(pool_size = (2,2), padding = 'valid'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 5, 5, 10)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'same'))\n",
    "model.add(MaxPooling2D(pool_size = (2,2), strides = (1,1), padding = 'valid'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 9, 9, 10)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'same'))\n",
    "model.add(AveragePooling2D(pool_size = (2,2), padding = 'valid'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 5, 5, 10)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# globalmaxpooling performs maxpooling over whole channel with depth = 1\n",
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'same'))\n",
    "model.add(GlobalMaxPooling2D())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 10)\n"
     ]
    }
   ],
   "source": [
    "# as the number of filters = 10, 10 values are returned as result of globalmaxpooling2D\n",
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Flattening\n",
    "- To be connected to fully connected layer (dense layer), convolutional/pooling layer should be **\"flattened\"**\n",
    "- Resulting shape = **(Number of instances, width X height X depth)**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'same'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 10, 10, 10)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model.add(Flatten())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 1000)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Fully Connected (Dense)\n",
    "- After flattening layer, fully connected layer can be added\n",
    "- output shape (number of nodes) should be designated"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "model.add(Conv2D(input_shape = (10, 10, 3), filters = 10, kernel_size = (3,3), strides = (1,1), padding = 'same'))\n",
    "model.add(Flatten())\n",
    "model.add(Dense(50))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 50)\n"
     ]
    }
   ],
   "source": [
    "print(model.output_shape)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
